home *** CD-ROM | disk | FTP | other *** search
/ Macwelt 1 / Macwelt DVD 1.toast / Web-Publishing / HTML-Editoren / Alpha ƒ / Tcl / Modes / spssMode.tcl < prev    next >
Encoding:
Text File  |  2001-01-26  |  60.3 KB  |  1,779 lines

  1. ## -*-Tcl-*-  (nowrap)
  2.  # ==========================================================================
  3.  #  Statistical Modes - an extension package for Alpha
  4.  # 
  5.  #  FILE: "spssMode.tcl"
  6.  #                                    created: 01/15/00 {07:15:32 pm} 
  7.  #                                last update: 01/26/01 {12:21:56 pm} 
  8.  #  Description: 
  9.  #                                
  10.  #  For SPSS syntax files.
  11.  # 
  12.  #  Author: Craig Barton Upright
  13.  #  E-mail: <cupright@princeton.edu>
  14.  #    mail: Princeton University,  Department of Sociology
  15.  #          Princeton, New Jersey  08544
  16.  #     www: <http://www.princeton.edu/~cupright>
  17.  #  
  18.  # -------------------------------------------------------------------
  19.  #  
  20.  # Copyright (c) 2000-2001  Craig Barton Upright
  21.  # 
  22.  # This program is free software; you can redistribute it and/or modify
  23.  # it under the terms of the GNU General Public License as published by
  24.  # the Free Software Foundation; either version 2 of the License, or
  25.  # (at your option) any later version.
  26.  # 
  27.  # This program is distributed in the hope that it will be useful,
  28.  # but WITHOUT ANY WARRANTY; without even the implied warranty of
  29.  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  30.  # GNU General Public License for more details.
  31.  # 
  32.  # You should have received a copy of the GNU General Public License
  33.  # along with this program; if not, write to the Free Software
  34.  # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  35.  # 
  36.  # ==========================================================================
  37.  ##
  38.  
  39. # ===========================================================================
  40. #
  41. # ◊◊◊◊ Initialization of SPSS mode ◊◊◊◊ #
  42.  
  43. alpha::mode SPSS 2.1.1 spssMenu {*.sps *.spss *.spp} {
  44.     spssMenu electricReturn electricTab electricBraces
  45. } {
  46.     # We require 7.4b21 for prefs handling.
  47.     alpha::package require -loose AlphaTcl 7.4b21
  48.     addMenu spssMenu "SPSS" SPSS
  49.     set unixMode(spss) {SPSS}
  50.     set modeCreator(SPSS) {SPSS}
  51. } uninstall {
  52.     this-file
  53. } help {
  54.     file "Statistical Modes Help"
  55. } maintainer {
  56.     "Craig Barton Upright" <cupright@princeton.edu> 
  57.     <http://www.princeton.edu/~cupright/>
  58. }
  59.  
  60. hook::register quitHook SPSS::quitHook
  61.  
  62. proc spssMenu {} {}
  63.  
  64. proc spssMode.tcl {} {}
  65.  
  66. namespace eval SPSS {}
  67.  
  68. # ===========================================================================
  69. #
  70. # ◊◊◊◊ Setting SPSS mode variables ◊◊◊◊ #
  71. #
  72.  
  73. # Removing obsolete preferences from earlier versions.
  74.  
  75. set oldvars {
  76.     addArguments addSymbols argumentColor don'tRemindMe electricTab
  77.     functionColor keywordColor spssHelp
  78. }
  79.  
  80. foreach oldvar $oldvars {prefs::removeObsolete SPSSmodeVars($oldvar)}
  81.  
  82. unset oldvar oldvars
  83.  
  84. # ===========================================================================
  85. #
  86. # Standard preferences recognized by various Alpha procs
  87. #
  88.  
  89. newPref var  fillColumn        {75}                SPSS
  90. newPref var  leftFillColumn    {0}                 SPSS
  91. newPref var  prefixString      {* }                SPSS
  92. newPref var  wordBreak         {[-a-zA-Z0-9\.]+}   SPSS
  93. newPref var  wordBreakPreface  {[^-a-zA-Z0-9\.]}   SPSS
  94. newPref flag wordWrap          {0}                 SPSS
  95.  
  96. # ===========================================================================
  97. #
  98. # Flag preferences
  99. #
  100.  
  101. # ===========================================================================
  102. #
  103. # Preferences to allow user to include additional commands, arguments, and
  104. # symbols through the Mode Preferences dialog.
  105.  
  106. newPref flag autoMark           {0}     SPSS    {SPSS::rebuildMenu spssMenu}
  107.  
  108. # Indent all continued commands, indicated by the lack of a period at
  109. # the end of a line, by the full indentation amount rather than half.
  110. newPref flag fullIndent         {1}     SPSS    {SPSS::rebuildMenu spssMenu}
  111.  
  112. # By default command double-click will send a command to on-line help, and
  113. # option double-click sends a command to the local SPSS application. 
  114. # Check this box to switch these key combinations.
  115. newPref flag localHelp          {0}     SPSS    {SPSS::rebuildMenu spssHelp}
  116.  
  117. # Check this box if your keyboard does not have a "Help" key.  This will
  118. # change some of the menu's key bindings.
  119. newPref flag noHelpKey          {0}     SPSS    {SPSS::rebuildMenu spssHelp}
  120.  
  121. # Set the list of flag preferences which can be changed in the menu.
  122.  
  123. set SPSSPrefsInMenu [list   \
  124.   "localHelp"               \
  125.   "noHelpKey"               \
  126.   "fullIndent"              \
  127.   ]
  128.  
  129. # ===========================================================================
  130. #
  131. # Variable preferences
  132.  
  133. # Enter additional SPSS keywords to be colorized.  These will also be
  134. # included in electric completions.
  135. newPref var addCommands         {}      SPSS    {SPSS::colorizeSPSS}
  136.  
  137. # Select the statistical application to be used.
  138. newPref var application         {SPSS}  SPSS    {SPSS::rebuildMenu spssMenu} [list PSPP SPSS]
  139.  
  140. # The "PSPP Home Page" menu item will send this url to your browser.
  141. newPref url psppHomePage        {http://www.gnu.org/software/pspp/}     SPSS
  142.  
  143. # Click on "Set" to find the local PSPP application.
  144. newPref sig psppSig             {}      SPSS
  145.  
  146. # Command double-clicking on an SPSS keyword will send it to this url
  147. # for a help reference page.
  148. newPref url helpUrl {http://www.gnu.org/cgi-bin/htsearch?words=pspp%2C+} SPSS
  149.     
  150. # The "SPSS Home Page" menu item will send this url to your browser.
  151. newPref url spssHomePage        {http://www.spss.com/}  SPSS
  152.  
  153. # Click on "Set" to find the local SPSS application.
  154. newPref sig spssSig             {SPSS}  SPSS
  155.  
  156. # ===========================================================================
  157. #
  158. # Color preferences
  159. #
  160. # Nomenclature notes:
  161. # SPSS does a lousy job of naming things, or at least is more than willing
  162. # to give a keyword (as in SPSS keyword) the same name as a function,
  163. # statement, subcommand or command.  There's little point in trying to
  164. # distinguish amongst all of this with different colors, because it just
  165. # won't work.  Instead, I'm just putting them all in one list, calling them
  166. # all "commands" and reminiscing about the days when S-Plus was my stats
  167. # package of choice.  The nomenclature of SPSS is only one of its several
  168. # limitations.
  169. #
  170.  
  171. # See the Statistical Modes Help file for an explanation of these different
  172. # categories, and lists of keywords.
  173. newPref color commandColor      {blue}   SPSS    {SPSS::colorizeSPSS}
  174. newPref color commentColor      {red}    SPSS    {stringColorProc}
  175. newPref color operatorColor     {blue}   SPSS    {SPSS::colorizeSPSS}
  176. newPref color stringColor       {green}  SPSS    {stringColorProc}
  177.  
  178. # The color of symbols such as +, -, /,  etc.
  179. newPref color symbolColor      {magenta} SPSS    {SPSS::colorizeSPSS}
  180.  
  181. regModeKeywords -e {*} -b {/*} {*/}         \
  182.   -c $SPSSmodeVars(commentColor)            \
  183.   -s $SPSSmodeVars(stringColor) SPSS {}
  184.  
  185. # ===========================================================================
  186. # Flag Flip
  187. # Called by menu items, change the value of flag preferences.
  188.  
  189. proc SPSS::flagFlip {pref} {
  190.  
  191.     global mode SPSSmodeVars
  192.  
  193.     set SPSSmodeVars($pref) [expr {$SPSSmodeVars($pref) ? 0 : 1}]
  194.     set oldMode $mode
  195.     set mode "SPSS"
  196.     synchroniseModeVar $pref $SPSSmodeVars($pref)
  197.     set mode $oldMode
  198.     if {$SPSSmodeVars($pref)} {
  199.         set end "on"
  200.     } else {
  201.         set end "off"
  202.     }
  203.     message "The \"$pref\" preference is now $end."
  204. }
  205.  
  206. # ===========================================================================
  207. # Comment Character variables for Comment Line / Paragraph / Box menu items.
  208.  
  209. set SPSS::commentCharacters(General)    [list "* "]
  210. set SPSS::commentCharacters(Paragraph)  [list "** " " **" " * "]
  211. set SPSS::commentCharacters(Box)        [list "*" 1 "*" 1 "*" 3]
  212.  
  213. # ===========================================================================
  214. #
  215. # ◊◊◊◊ Keyword Dictionaries ◊◊◊◊ #
  216. #
  217.  
  218. # Making sure that SPSSUserCommands exists.
  219. # This will be over-ridden if it is loaded from a ${mode}Prefs.tcl file.
  220. #
  221.  
  222. set SPSSUserCommands    ""
  223.  
  224. # ===========================================================================
  225. #
  226. # ◊◊◊◊   SPSS Commands   ◊◊◊◊ #
  227. #
  228.  
  229. set SPSSCommands {
  230.     a absolute add adevice adjred afreq after aggregate aic ainds align
  231.     alpha alsal analysis anova append approximate ar area ascii asresid
  232.     association automatic autorecode avalue average averf avonly awymmetic
  233.     backward badcorr barchart bart base basis baverage bcon bcov begin
  234.     beuclid binomial blank blanks blksize blwmn bmdp bmpd boick bootstrap
  235.     both boundary box boxm brau break breakdown brief brkspace bseuclid
  236.     bshape bstep btukey buffno calculate call categorical case casenum
  237.     cases cc cdfnorm cellinfo cells center centroid cfvar cha chalign
  238.     charend chdpace chebychev chicdf chisq chol choropleth ci cinterval
  239.     ckder clabels classify classplot clear clnr cluster cmax cmin cnames
  240.     cnlr cochran code colconf collect collin collinearity colspace column
  241.     columnwise combined comm comment compare complete compositional
  242.     compressed compression compute concat condense condensed condition
  243.     conditional config constrained content contents continued contour
  244.     contrast convert cook copy cor corff corr correlations cosine count cov
  245.     covariances covariates cpi criteria crossbreak crosstabs crshtol cssq
  246.     csum ctime.days ctime.hours ctime.minures cufreq cupct curpoints cusum
  247.     cutoff cweight d data date.dmy date.mdy date.moyr date.qur date.wkyr
  248.     date.yrday default define delta dendrogram density dependent
  249.     derivatives desc descending descending descriptives design det dev
  250.     deviation dfbeta dfe dfreq diag diagonal dice dictionary difference
  251.     digits dimenrdimens directions discrim discriminant disper display
  252.     distance divide document documents doend dollar double down draw dresid
  253.     drop dummy duncan duplicate durbin dvalue ebcdid econverge edit effects
  254.     efsize eigen eject else enclose end enter eof eps equamax error errors
  255.     estim eta euclid eval every exact examine exclude execute expected
  256.     experimental export external extraction f facilities factor fgtmlr
  257.     fieldnames file files fin fin finish first first fixed flip flt fnames
  258.     footnote for formats fortran forward fout fpair fprecision freq
  259.     frequencies friedman from frspace fscore fstep ftolerance full
  260.     functions gamma gcmdfile gcov gdata gdevice gemscal get gg ginv gls
  261.     gmemory graph great gresid grouped groups groups groupwise gsch guttman
  262.     hamann handle harmonic hazard hbar head header helmert help hf hicicle
  263.     hierarchical higher highest hiloglinear histogram history hold
  264.     homogeneity horizontal host hotelling hsize hypoth id ident if image
  265.     import in include increment indicator individual indscal info initial
  266.     inline input input intermed interval intervals into inv istep iter
  267.     iterate jaccard jdate joint journal k-s k-w k1 k2 kaiser kappa keep
  268.     kendall key keyed kmo kroneker kurtosis label labels lag lambda last
  269.     lcon least leave left length let level lever lftolerance limit line
  270.     linearity list listing listwise log logistic logit loglinear logsurv
  271.     loop loss lower lowest lpad lpi lresid lsd lstolerance ltrim m-wm
  272.     macros magic mahal make manova manual map match matrix maxorders
  273.     maxsteps mconvert mde mean means merge mestimates method missing mixed
  274.     mode model more moses mprint mrgroup msave mssq msum mult multiple
  275.     multiply multipunch multiv multivariate muplus mwithin mxerrs mxloops
  276.     mxwarns n n_matrix n_scalar n_vector name names naname nanames natres
  277.     navallabs ncol ncomp negative nested new newnames newnames newpage
  278.     nftolerance ngt nin nlr nlr nmiss no nobox nocatlabs nodiagonal noend
  279.     noexpand noindex noinitial nokaiser nolabels nolist nominal none
  280.     nonmissing nonpar noorigin noprint normal normplot normprob norotate
  281.     nosig nostep notable noulb noupdate novalues nowarn npar nrow ntiles nu
  282.     null nulline number numbered numeric numiss nvalid oblimin occurs
  283.     ochaiai of off offexpand offset omeans onepage onetail oneway oneway
  284.     oneway onexpand optimal options optolerance ordered ordinal origin
  285.     orthonorm osiris other out outfile outliers output outs overlay
  286.     overview p pa1 pa2 paf page paired pairs pairwise parall parallel
  287.     parameters partial partialplot partition pattern pc pcomps pcon pct
  288.     pearson percent percentiles pgroup pgt ph2 phi pie pin pin plain plot
  289.     plt pmeans point polynomial pool pooled positional pout power pred
  290.     preserve presorted previous print printback priors prism probit
  291.     procedure procedures proportion prox proximities ptile pyramid q
  292.     quartiles quartimax quick quick quick quote r radial range ranges rank
  293.     ration raw rcon rconverge recode rectangular reduncancy reformat reg
  294.     regression regwgt release reliability remove rename repeat repeating
  295.     replace report reread rescale reshape resid residual residuals response
  296.     responses restore results reverse rfraction rfraction right rindex risk
  297.     rlabels rmax rmin rmp rnames rnkorder rotate rotation row rowconf rows
  298.     rpad rr rssq rsum rt rtrim runs sample sas saslib savage save scale
  299.     scan scatterplot schedule scheffe scompression scratch scss sd sdresid
  300.     seed sekurt select semean separate serdiag serial ses seskew set
  301.     seuclid shape show sig sign signif significance simple since single
  302.     singledf size skewness skip sm snames snk solve sort space space
  303.     spearman special split spread spred spss sresid sscon sscp sstype
  304.     stacked stan standardize starts statistics status stddev step stepdown
  305.     steplimit stepwise stimwght stressmin strictparallel string strings
  306.     substr substring subtitle subtract sum summary sumspace survival sval
  307.     svd sweep symbols symmetric sysmix t t-test table tables tail tape tb1
  308.     tb2 tbfonts tcdf tcov temporary terminal test tests then ties tiestore
  309.     time time.days time.hms title tokens tolerance total transformations
  310.     translate tspace tukey twotail type type uc uls unclassified
  311.     uncompressed unconditional undefined underscore uniform unique univ
  312.     univariate univf unnumbered unquote unselected up upcase update validn
  313.     value values var variable variables variance varimax vars vector
  314.     vertical vicile view vin vs vsize w-w ward warn waverage weight width
  315.     wilcoxon wild workfile write wsdesign wsfactors xdate.date xdate.hour
  316.     xdate.jday xdate.mday xdate.minute xdate.month xdate.quarter
  317.     xdate.second xdate.tday xdate.time xdate.week xdate.wkday xdate.year
  318.     xmdend xprod xsave xsort xtx y yes yrmoda z z zcorr zpp zpred zresid
  319. }
  320.  
  321. # ===========================================================================
  322. #
  323. # ◊◊◊◊   SPSS Functions   ◊◊◊◊ #
  324. #
  325.  
  326. set SPSSFunctions {
  327.     abs arsin artan cos exp lg10 ln mod rnd sin sqrt trunc
  328. }
  329.  
  330.     
  331. # ===========================================================================
  332. #
  333. # ◊◊◊◊   SPSS Operators   ◊◊◊◊ #
  334. #
  335.  
  336. set SPSSOperators {
  337.     all and by eq ge gt into le lt ne not or .por .sav .sps thru to with
  338.     xls
  339. }
  340.  
  341. # ===========================================================================
  342. # Colorize SPSS.
  343. # Set all keyword lists, and colorize.
  344. # Could also be called in a <mode>Prefs.tcl file
  345.  
  346. proc SPSS::colorizeSPSS {{pref ""}} {
  347.     
  348.     global SPSSmodeVars SPSSCommands SPSSFunctions SPSSOperators SPSSUserCommands 
  349.     
  350.     global SPSSlowerCaseCommands SPSSupperCaseCommands
  351.     global SPSSlowerCaseFunctions SPSSupperCaseFunctions
  352.     global SPSSlowerCaseCmds SPSScmds
  353.     
  354.     # Create the list of all keywords for completions.  SPSS keywords
  355.     # are not case-sensitive.  To allow for different user styles,
  356.     # we'll include lower case commands as well as ALL CAPS.
  357.     message "Creating ALL CAP commands for SPSS mode …"
  358.     # Commands only
  359.     set SPSSlowerCaseCommands [concat \
  360.       $SPSSCommands $SPSSmodeVars(addCommands) $SPSSUserCommands \
  361.       ]
  362.     set SPSSupperCaseCommands [string toupper $SPSSlowerCaseCommands]
  363.     # Functions only
  364.     set SPSSlowerCaseFunctions  $SPSSFunctions
  365.     set SPSSupperCaseFunctions [string toupper $SPSSlowerCaseFunctions]
  366.     
  367.     set SPSSlowerCaseCmds [lsort [lunique [concat \
  368.       $SPSSlowerCaseCommands $SPSSlowerCaseFunctions \
  369.       ]]]
  370.  
  371.     # SPSScmds
  372.     set SPSScmds [lsort [lunique [concat \
  373.       $SPSSlowerCaseCommands $SPSSupperCaseCommands $SPSSlowerCaseFunctions \
  374.       $SPSSupperCaseFunctions \
  375.       ]]]
  376.     message ""
  377.  
  378.     # Commands
  379.     regModeKeywords -a -k $SPSSmodeVars(commandColor) SPSS $SPSScmds
  380.     
  381.     # Operators
  382.     regModeKeywords -a                                                  \
  383.       -k $SPSSmodeVars(operatorColor) SPSS $SPSSOperators
  384.  
  385.     # Symbols
  386.     regModeKeywords -a                                                  \
  387.       -k $SPSSmodeVars(symbolColor) SPSS {|}                            \
  388.       -i "+" -i "-" -i "_" -i "\\"                                      \
  389.       -I $SPSSmodeVars(symbolColor)
  390.  
  391.     if {$pref != ""} {refresh}
  392. }
  393.  
  394. # Call this now.
  395.  
  396. SPSS::colorizeSPSS
  397.  
  398. # ===========================================================================
  399. #
  400. # Reload Completions.  
  401. # This is now an obsolete proc.
  402.  
  403. proc SPSS::reloadCompletions {} {
  404.     alertnote "\"SPSS::reloadCompletions\" is an obsolete proc.\
  405.       It should be removed from your SPSSPrefs.tcl file."
  406. }
  407.  
  408. # ===========================================================================
  409. #
  410. # ◊◊◊◊ Key Bindings, Electrics ◊◊◊◊ #
  411. #
  412.  
  413. # Known bug: Key-bindings from other global menus might conflict with those
  414. # defined in the SPSS menu.  This will help ensure that this doesn't happen.
  415.  
  416. Bind 'n'    <sz>    {SPSS::nextCommand} SPSS
  417. Bind 'p'    <sz>    {SPSS::prevCommand} SPSS
  418. Bind 's'    <sz>    {SPSS::selectCommand} SPSS
  419. Bind 'c'    <sz>    {SPSS::copyCommand} SPSS
  420.  
  421. Bind 'i'    <cz>    {SPSS::reformatCommand} SPSS
  422.  
  423. Bind '\)'           {SPSS::electricRight "\)"} SPSS
  424.  
  425. # For those that would rather use arrow keys to navigate:
  426.  
  427. Bind    up  <sz>    {SPSS::prevCommand 0 0} SPSS
  428. Bind  left  <sz>    {SPSS::prevCommand 0 1} SPSS
  429. Bind  down  <sz>    {SPSS::nextCommand 0 0} SPSS
  430. Bind right  <sz>    {SPSS::nextCommand 0 1} SPSS
  431.  
  432. # ===========================================================================
  433. # SPSS Carriage Return
  434. # Inserts a carriage return, and indents properly.
  435.  
  436. proc SPSS::carriageReturn {} {
  437.     
  438.     global SPSSmodeVars
  439.     
  440.     if {[isSelection]} {
  441.         deleteSelection
  442.     } 
  443.     set pos1 [lineStart [getPos]]
  444.     set pos2 [getPos]
  445.     if {[regexp {^([\t ])*(\}|\))} [getText $pos1 $pos2]]} {
  446.         createTMark temp $pos2
  447.         catch {bind::IndentLine}
  448.         gotoTMark temp ; removeTMark temp
  449.     } 
  450.     insertText "\r"
  451.     catch {bind::IndentLine}
  452. }
  453.  
  454. # ===========================================================================
  455. #
  456. # SPSS Electric Left, Right
  457. # Adapted from "tclMode.tcl"
  458.  
  459. proc SPSS::electricLeft {} {
  460.     
  461.     if {[literalChar]} {
  462.         typeText "\{"
  463.         return
  464.     }
  465.     set pat "\}\[ \t\r\n\]*(else(if)?)\[ \t\r\n\]*\$"
  466.     set pos [getPos]
  467.     if { [set result [findPatJustBefore "\}" $pat $pos word]] == "" } { 
  468.         insertText "\{"
  469.         return
  470.     }
  471.     # we have an if/else(if)/else
  472.     switch -- $word {
  473.         "else" {
  474.             deleteText [lindex $result 0] $pos
  475.             elec::Insertion "\} $word \{\r\t••\r\}\r••"
  476.         }
  477.         "elseif" {
  478.             deleteText [lindex $result 0] $pos
  479.             elec::Insertion "\} $word \{••\} \{\r\t••\r\}\r••"
  480.         }
  481.     }
  482. }
  483.  
  484. proc SPSS::electricRight {{char "\}"}} {
  485.     
  486.     if {[literalChar]} {
  487.         typeText $char
  488.         return
  489.     }
  490.     set pos [getPos]
  491.     typeText $char
  492.     if {![regexp {[^ \t]} [getText [lineStart $pos] $pos]]} {
  493.         set pos [lineStart $pos]
  494.         createTMark temp [getPos]
  495.         catch {bind::IndentLine}
  496.         gotoTMark temp ; removeTMark temp
  497.         bind::CarriageReturn
  498.     } 
  499.     if {[catch {blink [matchIt $char [pos::math $pos - 1]]}]} {
  500.         beep ; message "No matching $char !!"
  501.     } 
  502. }
  503.  
  504. # ===========================================================================
  505. #
  506. # ◊◊◊◊ Indentation ◊◊◊◊ #
  507. # SPSS::correctIndentation is necessary for Smart Paste, and returns the
  508. # correct level of indentation for the current line.  SPSS::indentLine uses
  509. # this level to indent the current line.
  510. # We have two level of indentation in SPSS, for the continuation of
  511. # commands, in which case we simply indent to the amount of the SPSS mode
  512. # variable indentationAmount, and for nested braces.
  513. # In SPSS::correctIndentation, we grab the previous non-commented line,
  514. # remove all of the characters besides braces and quotes, and then convert
  515. # it all to a list to be evaluated.  Braces contained within quotes, as
  516. # well as literal characters, should all be ignored and the remaining
  517. # braces are used to determine the correct level of nesting.
  518.  
  519. proc SPSS::indentLine {{pos ""}} {
  520.     
  521.     if {$pos == ""} {set pos [getPos]} 
  522.     # Get details of current line.
  523.     set posBeg [lineStart [getPos]]
  524.     set text [getText $posBeg [nextLineStart $posBeg]]
  525.     regexp {^[ \t]*} $text white 
  526.     set posNext1 [pos::math $posBeg + [string length $white]]
  527.     set posNext2 [pos::math $posNext1 + 1]
  528.     if {[pos::compare $posNext2 > [maxPos]]} {
  529.         set posNext2 [maxPos]
  530.     } 
  531.     # Determine the correct level of indentation for this line, given the
  532.     # next character.
  533.     set lwhite [SPSS::correctIndentation $pos [getText $posNext1 $posNext2]]
  534.     set lwhite [text::indentOf $lwhite]
  535.     if {$white != $lwhite} {
  536.         replaceText $posBeg $posNext1 $lwhite
  537.     }
  538.     goto [pos::math $posBeg + [string length $lwhite]]
  539. }
  540.  
  541. proc SPSS::correctIndentation {pos {next ""}} {
  542.     
  543.     global mode indent_amounts SPSSmodeVars
  544.     
  545.     if {$mode == "SPSS"} {
  546.         set continueIndent [expr {$SPSSmodeVars(fullIndent) + 1}]
  547.     } else {
  548.         set continueIndent 2
  549.     } 
  550.  
  551.     set posBeg   [lineStart $pos]
  552.     # Get information about this line, previous line ...
  553.     set thisLine  [SPSS::getCommandLine $posBeg 1 1]
  554.     set prevLine1 [SPSS::getCommandLine [pos::math $posBeg - 1] 0 1]
  555.     set prevLine2 [SPSS::getCommandLine [pos::math [lindex $prevLine1 0] - 1] 0 1]
  556.     set lwhite    [lindex $prevLine1 1]
  557.     # If we have a previous line ...
  558.     if {[pos::compare [lindex $prevLine1 0] != $posBeg]} {
  559.         set pL1 [string trim [lindex $prevLine1 2]]
  560.         # Indent if the last line did not terminate the command.
  561.         if {![regexp {\.([\t ]?)$} $pL1]} {
  562.             incr lwhite $indent_amounts($continueIndent)
  563.         } 
  564.         # Check to make sure that the previous command was not itself a
  565.         # continuation of the line before it.
  566.         if {[pos::compare [lindex $prevLine1 0] != [lindex $prevLine2 0]]} {
  567.             set pL2 [string trim [lindex $prevLine2 2]]
  568.             if {![regexp {\.([\t ]?)$} $pL2]} {
  569.                 incr lwhite $indent_amounts(-$continueIndent)
  570.             } 
  571.         }
  572.         # Find out if there are any unbalanced {,},(,) in the last line.
  573.         regsub -all {[^ \{\}\(\)\"\*\/\\]} $pL1 { } line
  574.         # Remove all literals.
  575.         regsub -all {\\\{|\\\}|\\\(|\\\)|\\\"|\\\*|\\\/} $line { } line
  576.         regsub -all {\\} $line { } line
  577.         # Remove everything surrounded by quotes.
  578.         regsub -all {\"([^\"]+)\"} $line { } line
  579.         regsub -all {\"} $line { } line
  580.         # Remove everything surrounded by bracketed comments.
  581.         regsub -all {/\*([^\*/]+)\*/} $line { } line
  582.         # Now turn all braces into 2's and -2's
  583.         regsub -all {\{|\(} $line { 2 }  line
  584.         regsub -all {\}|\)} $line { -2 } line
  585.         # This list should now only contain 2's and -2's.
  586.         foreach i $line {
  587.             if {$i == "2" || $i == "-2"} {incr lwhite $indent_amounts($i)} 
  588.         }
  589.         # Did the last line start with a lone \) or \} ?  If so, we want to
  590.         # keep the indent, and not make call it an unbalanced line.
  591.         if {[regexp {^[\t ]*(\}|\))} $pL1]} {
  592.             incr lwhite $indent_amounts(2)
  593.         } 
  594.     } 
  595.     # If we have a current line ...
  596.     if {[pos::compare [lindex $thisLine 0] == $posBeg]} {
  597.         # Reduce the indent if the first non-whitespace character of this
  598.         # line is ) or \}.
  599.         set tL [lindex $thisLine 2]
  600.         if {$next == "\}" || $next == ")" || [regexp {^[\t ]*(\}|\))} $tL]} {
  601.             incr lwhite $indent_amounts(-2)
  602.         } 
  603.     } 
  604.     # Now we return the level to the calling proc.
  605.     return [expr {$lwhite > 0 ? $lwhite : 0}]
  606. }
  607.  
  608. # ===========================================================================
  609. # Get Command Line
  610. # Find the next/prev command line relative to a given position, and return
  611. # the position in which it starts, its indentation, and the complete text
  612. # of the command line.  If the search for the next/prev command fails,
  613. # return an indentation level of 0.
  614. # We have the luxury here of ignore any previous/next commented lines.
  615.  
  616. proc SPSS::getCommandLine {pos {direction 1} {ignoreComments 1}} {
  617.     
  618.     if {$ignoreComments} {
  619.         set pat {^[\t ]*[^\t\r\n\*/ ]}
  620.     } else {
  621.         set pat {^[\t ]*[^\t\r\n ]}
  622.     } 
  623.     set posBeg [pos::math [lineStart $pos] - 1]
  624.     if {[pos::compare $posBeg < [minPos]]} {
  625.         set posBeg [minPos]
  626.     } 
  627.     set lwhite 0
  628.     if {![catch {search -f $direction -r 1 $pat $pos} match]} {
  629.         set posBeg [lindex $match 0]
  630.         set lwhite [posX [pos::math [lindex $match 1] - 1]]
  631.     }
  632.     set posEnd [pos::math [nextLineStart $posBeg] - 1]
  633.     if {[pos::compare $posEnd > [maxPos]]} {
  634.         set posEnd [maxPos]
  635.     } 
  636.     return [list $posBeg $lwhite [getText $posBeg $posEnd]]
  637. }
  638.  
  639. # ===========================================================================
  640. # ◊◊◊◊ Command Double Click ◊◊◊◊ #
  641. #
  642. # Checks to see if the highlighted word appears in any keyword list, and if
  643. # so, sends the selected word to the www.SPSS.com help site.
  644. # Control-Command double click will insert syntax information in status bar.
  645. # Shift-Command double click will insert commented syntax information in window.
  646. # (The above is not yet implemented -- need to enter all of the syntax info.)
  647.  
  648. proc SPSS::DblClick {from to shift option control} {
  649.     
  650.     global SPSSmodeVars SPSScmds SPSSSyntaxMessage
  651.         
  652.     select $from $to
  653.     set command [getSelect]
  654.     
  655.     if {[lsearch -exact $SPSScmds $command] == -1} {
  656.         message "\"$command\" is not defined as a SPSS system keyword."
  657.         return
  658.     }
  659.     # Any modifiers pressed?
  660.     if {$control} {
  661.         # CONTROL -- Just put syntax message in status bar window
  662.         if {[info exists SPSSSyntaxMessage($command)]} {
  663.             message "$SPSSSyntaxMessage($command)"
  664.         } else {
  665.             message "Sorry, no syntax information available for $command"
  666.         } 
  667.     } elseif {$shift} {
  668.         # SHIFT --Just insert syntax message as commented text
  669.         if {[info exists SPSSSyntaxMessage($command)]} {
  670.             endOfLine
  671.             insertText "\r"
  672.             insertText "$SPSSSyntaxMessage($command)"
  673.             comment::Line
  674.         } else {
  675.             message "Sorry, no syntax information available for $command"
  676.         } 
  677.     } elseif {$option && !$SPSSmodeVars(localHelp)} {
  678.         # Now we have four possibilities, based on "option" key and the
  679.         # preference for "local Help Only".  (Local Help Only actually
  680.         # switches the "normal" behavior of options versus not.)
  681.         # 
  682.         # OPTION, local help isn't checked -- Send command to local application
  683.         SPSS::localCommandHelp $command
  684.     } elseif {$option && $SPSSmodeVars(localHelp)} {
  685.         # OPTION, but local help is checked -- Send command for on-line help.
  686.         SPSS::wwwCommandHelp $command
  687.     } elseif {$SPSSmodeVars(localHelp)} {
  688.         # No modifiers, local help is checked -- Send command to local app.
  689.         SPSS::localCommandHelp $command
  690.     } else {
  691.         # No modifiers, no local help checked -- Send command for on-line
  692.         # help.  This is the "default" behavior.
  693.         SPSS::wwwCommandHelp $command
  694.     }
  695. }
  696.  
  697. # ===========================================================================
  698. # WWW Command Help
  699. # Send command to defined url, prompting for text if necessary.
  700.  
  701. proc SPSS::wwwCommandHelp {{command ""}} {
  702.     
  703.     global SPSSmodeVars
  704.     
  705.     if {$command == ""} {
  706.         set command [prompt "on-line SPSS/PSPP help for ... " [getSelect]] 
  707.         # set command [statusPrompt "on-line help for ... " ] 
  708.     } 
  709.     message "\"$command\" sent to $SPSSmodeVars(helpUrl)"
  710.     url::execute $SPSSmodeVars(helpUrl)$command
  711. }
  712.  
  713. # ===========================================================================
  714. # Local Command Help
  715. # Send command to local application, prompting for text if necessary.
  716.  
  717. proc SPSS::localCommandHelp {{command ""} {app ""}} {
  718.     
  719.     SPSS::betaMessage
  720.     
  721.     global SPSSmodeVars tcl_platform
  722.     
  723.     if {$app == ""} {
  724.         set app $SPSSmodeVars(application)
  725.     } 
  726.     if {$command == ""} {
  727.         set command [prompt "local $app application help for ... " [getSelect]]
  728.         # set command [statusPrompt "local S-Plus application help for ..." ]
  729.     }
  730.     set pf $tcl_platform(platform)
  731.  
  732.     if {$pf == "macintosh"} {
  733.         # Make sure that the Macintosh application for the signature exists.
  734.         if {[catch {[nameFromAppl [SPSS::sig $app]]}]} {
  735.             SPSS::selectApplication $app
  736.         } 
  737.     } elseif {$pf == "windows" || $pf == "unix"} {
  738.         # Make sure that the Windows application for the signature exists. 
  739.         # We assume that this will work for unix, too.
  740.         if {![file exists [SPSS::sig $app]]} {
  741.             SPSS::selectApplication $app
  742.         } 
  743.     }
  744.     # Now we look for the actual help file.
  745.     if {![file exists $helpFile]} {
  746.         beep ; message "Sorry, no help file for \"$command\" was found."
  747.         error "No help file found for \"$command\"."
  748.     } else {
  749.         help::openFile $helpFile 
  750.     } 
  751. }
  752.  
  753. # ===========================================================================
  754. #
  755. # ◊◊◊◊ Mark File and Parse Functions ◊◊◊◊ #
  756. #
  757.  
  758. # ===========================================================================
  759. #
  760. # SPSS Mark File
  761. # This will return the first 35 characters from the first non-commented
  762. # word that appears in column 0.  All other output files (those not
  763. # recognized) will take into account the additional left margin elements
  764. # added by SPSS/PSPP.
  765. #
  766.  
  767. proc SPSS::MarkFile {{type ""}} {
  768.     
  769.     removeAllMarks
  770.     
  771.     message "Marking File …"
  772.     
  773.     set pos [minPos]
  774.     set count 0
  775.     # Figure out what type of file this is -- source, frequency, or output.
  776.     # The variable "type" refers to a call from the SPSS menu.
  777.     # Otherwise we try to figure out the type based on the file's suffix.
  778.     if {$type == ""} {
  779.         if {[win::CurrentTail] == "* SPSS Mode Example *"} {
  780.             # Special case for Mode Examples, but only if called from
  781.             # Marks menu.  (Called from SPSS menu, "type" will over-ride.)
  782.             set type  ".sps"
  783.         } else {
  784.             set type [file extension [win::CurrentTail]]
  785.         }
  786.     }
  787.     # Set the mark expression.
  788.     if {$type == ".sps"} {
  789.         # Is this a source file?
  790.         set markExpr {^(\*\*\*[ ]|\*\*\*\*[ ])?[a-zA-Z]}
  791.     } elseif {$type == ".freq"} {
  792.         # Is this a frequencies file?  Determining what is truly a variable
  793.         # in SPSS output is not straightforward.  This regexp is a little
  794.         # particular, and might only apply to unix output.
  795.         set markExpr {^.+[\r\n]+[ ]+(Valid )}
  796.         catch {set pos [lindex [search -f 1 -m 0 -i 1 {freq} [minPos]] 0]}
  797.     } else {
  798.         # Assume that it's output.
  799.         set markExpr {^[ ]+[0-9]+(  )(0  )*(\*\*\*[ ]|\*\*\*\*[ ])?[a-zA-Z]}
  800.     }
  801.     # Now mark the file.
  802.     while {![catch {search -f 1 -r 1 -m 0 $markExpr $pos} match]} {
  803.         if {$type == ".freq"} {
  804.             set posBeg [lineStart [lindex $match 0]]
  805.             set posEnd [nextLineStart $posBeg]
  806.             set line   [string trimright [getText $posBeg $posEnd]]
  807.             regsub {[ ]+.+$} $line {} line
  808.             message "# of variables: [incr count]"
  809.         } else {
  810.             incr count
  811.             set posBeg [lindex $match 0]
  812.             set posEnd [nextLineStart $posBeg]
  813.             if {[pos::compare $posEnd > [maxPos]]} {set posEnd [maxPos]} 
  814.             set line [string trimright [getText $posBeg $posEnd]]
  815.             # Get rid of the leading "  [0-9]  " for output files
  816.             if {$type != ".sps"} {
  817.                 regsub {^[ ]+([0-9]*[0-9]*[0-9]*[0-9])} $line {} line
  818.                 regsub {^  0} $line {} line
  819.             }
  820.             # Get rid of braces.
  821.             regsub -all {\{|\[} $line {(} line
  822.             regsub -all {\}|\]} $line {)} line
  823.             # Add a little indentation so that section marks show up better
  824.             set line [string trimleft $line " "]
  825.             set line  "  $line"
  826.             if {[regsub {  \*\*\*\* } $line {* } line]} {
  827.                 incr count -1
  828.             } elseif {[regsub {  \*\*\* } $line {• } line]} {
  829.                 incr count -1
  830.             } 
  831.             if {[string length $line] > 35} {
  832.                 set line "[string range $line 0 35] ..."
  833.             } else {
  834.                 # Get rid of trailing sem-colons.
  835.                 set line  [string trimright $line ";" ]
  836.             }
  837.         }
  838.         # If the mark starts with "execute", ignore it.
  839.         if {![regexp {^  (execute|EXECUTE)} $line]} {
  840.             setNamedMark $line $posBeg $posBeg $posBeg
  841.         } 
  842.         set pos $posEnd
  843.     }
  844.     # Sorting the marks if this is a frequencies file.
  845.     # (Code lifted from "sortMarksFile", in "marks.tcl")
  846.     if {$type == ".freq"} {
  847.         message "Sorting marks …"
  848.         set mks {}
  849.         foreach mk [getNamedMarks] {
  850.             removeNamedMark -n [lindex $mk 0] -w [lindex $mk 1]
  851.             lappend mks $mk
  852.         }
  853.         foreach mk   [lsort $mks] {
  854.             set name [lindex $mk 0]
  855.             set disp [lindex $mk 2]
  856.             set pos  [lindex $mk 3]
  857.             set end  [lindex $mk 4]
  858.             
  859.             setNamedMark $name $disp $pos $end
  860.         }
  861.         message "This frequencies file describes $count variables."
  862.     } else {
  863.         message "This file contains $count commands."
  864.     } 
  865. }
  866.  
  867. # ===========================================================================
  868. #
  869. # SPSS Parse Functions
  870. # This will return only the SPSS command names.
  871.  
  872. proc SPSS::parseFuncs {} {
  873.     
  874.     global sortFuncsMenu    
  875.     
  876.     if {[file extension [win::CurrentTail]] == ".sps" } {
  877.         set funcExpr {^(\w+)}
  878.     } elseif {[file tail [win::Current]] == "* SPSS Mode Example *"} {
  879.         # Special case for Mode Examples folder
  880.         set funcExpr {^(\w+)}
  881.     } else {
  882.         # Assume that it's output.
  883.         set funcExpr {^([ ]+[0-9]+(  )(0  )*)([a-zA-Z]+[a-zA-Z])}
  884.     }
  885.     set pos [minPos]
  886.     set m {}
  887.     while {[set match [search -s -f 1 -r 1 -i 0 -n $funcExpr $pos]] != ""} {
  888.         if {[regexp -- $funcExpr [eval getText $match] "" "" "" "" word]} {
  889.             lappend m [list $word [lindex $match 0]]
  890.         }
  891.         set pos [lindex $match 1]
  892.     }
  893.     if {$sortFuncsMenu} {
  894.         regsub -all "\[\{\}\]" [lsort -ignore $m] "" m
  895.     } else {
  896.         regsub -all "\[\{\}\]" $m "" m
  897.     }   
  898.     return  $m
  899. }
  900.  
  901. # ===========================================================================
  902. # ◊◊◊◊ -------------------- ◊◊◊◊ #
  903. # ◊◊◊◊ SPSS Menu ◊◊◊◊ #
  904. # based upon the Stata menu, contributed by 
  905. # L. Phillip Schumm <pschumm@uchicago.edu>
  906.  
  907. # Tell Alpha what procedures to use to build all menus, submenus.
  908.  
  909. menu::buildProc spssMenu            SPSS::buildMenu
  910. menu::buildProc spssHelp            SPSS::buildHelpMenu
  911. menu::buildProc psppHelp            SPSS::buildHelpMenu
  912. menu::buildProc spssKeywords        SPSS::buildKeywordsMenu
  913. menu::buildProc markSpssFileAs…     SPSS::buildMarkMenu
  914. menu::buildProc markPsppFileAs…     SPSS::buildMarkMenu
  915.  
  916. # First build the main SPSS menu.
  917.  
  918. proc SPSS::buildMenu {} {
  919.     
  920.     global spssMenu SPSSmodeVars
  921.     
  922.     set app    [SPSS::menuAppName]
  923.     set lowApp [string tolower $app]
  924.     
  925.     set menuList [list                                  \
  926.       "${lowApp}HomePage"                               \
  927.       "/S<U<OswitchTo${app}"                            \
  928.       [list Menu -n ${lowApp}Help       -M SPSS {}]     \
  929.       "(-"                                              \
  930.       [list Menu -n spssKeywords        -M SPSS {}]     \
  931.       [list Menu -n mark${app}FileAs…   -M SPSS {}]     \
  932.       "(-"                                              \
  933.       "/P<U<OprocessFile"                               \
  934.       "/P<U<O<BprocessSelection"                        \
  935.       "(-"                                              \
  936.       "/I<U<OinsertPath"                                \
  937.       "(-"                                              \
  938.       "/N<U<BnextCommand"                               \
  939.       "/P<U<BprevCommand"                               \
  940.       "/S<U<BselectCommand"                             \
  941.       "/I<B<OreformatCommand"                           \
  942.       ]
  943.     set submenus [list mark${app}FileAs… ${lowApp}Help spssKeywords]
  944.     return       [list build $menuList SPSS::menuProc $submenus $spssMenu]
  945. }
  946.  
  947. # Manipulate the application's name for menu purposes.
  948.  
  949. proc SPSS::menuAppName {{app ""}} {
  950.     
  951.     global SPSSmodeVars
  952.     
  953.     if {$app == ""} {
  954.         set app [string toupper $SPSSmodeVars(application)]
  955.     } 
  956.     if {$app == "SPSS"} {
  957.         return "Spss"
  958.     } else {
  959.         return "Pspp"
  960.     } 
  961. }
  962.  
  963. # Then build the "SPSS Help" submenu.
  964.  
  965. proc SPSS::buildHelpMenu {} {
  966.     
  967.     global SPSSmodeVars SPSSPrefsInMenu alpha::platform
  968.     
  969.     # Determine which key should be used for "Help", with F8 as option.
  970.     
  971.     if {!$SPSSmodeVars(noHelpKey)} {
  972.         set key "/t"
  973.     } else {
  974.         set key "/l"
  975.     } 
  976.     
  977.     # Reverse the local, www key bindings depending on the value of the
  978.     # 'Local Help" variable.
  979.     
  980.     if {!$SPSSmodeVars(localHelp)} {
  981.         set menuList [list                  \
  982.           "${key}<OwwwCommandHelp…"         \
  983.           "${key}<IlocalCommandHelp…"       \
  984.           ]
  985.     } else {
  986.         set menuList [list                  \
  987.           "${key}<OlocalCommandHelp…"       \
  988.           "${key}<IwwwCommandHelp…"         \
  989.           ]
  990.     } 
  991.     lappend menuList "(-"
  992.     if {$SPSSmodeVars(application) == "SPSS"} {
  993.         lappend menuList "pspp"
  994.         lappend menuList "!•spss"
  995.     } else {
  996.         lappend menuList "!•pspp"
  997.         lappend menuList "spss"
  998.     }
  999.     lappend menuList "(-"
  1000.     if {${alpha::platform} == "alpha"} {
  1001.         set prefix "!√"
  1002.     } else {
  1003.         set prefix "!•"
  1004.     } 
  1005.     foreach pref $SPSSPrefsInMenu {
  1006.         if {$SPSSmodeVars($pref)} {
  1007.             lappend menuList "${prefix}$pref"
  1008.         } else {
  1009.             lappend menuList "$pref"
  1010.         } 
  1011.     }
  1012.     lappend menuList "(-"
  1013.     lappend menuList "setPsppApplication"
  1014.     lappend menuList "setSpssApplication"
  1015.     lappend menuList "(-"
  1016.     lappend menuList "${key}<BspssModeHelp"
  1017.     
  1018.     return [list build $menuList SPSS::helpProc {}]
  1019. }
  1020.  
  1021. # Then build the "SPSS Mode Keywords" submenu.
  1022.  
  1023. proc SPSS::buildKeywordsMenu {} {
  1024.     
  1025.     set menuList [list                  \
  1026.       "listKeywords"                    \
  1027.       "checkKeywords"                   \
  1028.       "addNewCommands"                  \
  1029.       ]
  1030.     return [list build $menuList SPSS::keywordsProc {}]
  1031. }
  1032.  
  1033. # Then build the "Mark SPSS File As" submenu.
  1034.  
  1035. proc SPSS::buildMarkMenu {} {
  1036.     
  1037.     global SPSSmodeVars alpha::platform
  1038.     
  1039.     set menuList [list                  \
  1040.       "source"                          \
  1041.       "output"                          \
  1042.       "freqFile"                        \
  1043.       "(-"                              \
  1044.       ]
  1045.     if {${alpha::platform} == "alpha"} {
  1046.         set prefix "!√"
  1047.     } else {
  1048.         set prefix "!•"
  1049.     } 
  1050.     if {$SPSSmodeVars(autoMark)} {
  1051.         lappend menuList "${prefix}autoMark"
  1052.     } else {
  1053.         lappend menuList "autoMark"        
  1054.     }
  1055.     return [list build $menuList SPSS::markFileProc {}]
  1056. }
  1057.  
  1058. proc SPSS::rebuildMenu {{menuName "spssMenu"} {pref ""}} {
  1059.     menu::buildSome $menuName
  1060. }
  1061.  
  1062. # Dim some menu items when there are no open windows.
  1063. set menuItems {
  1064.     processFile processSelection markSpssFileAs markPsppFileAs
  1065.     insertPath 
  1066.     nextCommand prevCommand selectCommand
  1067. }
  1068. foreach i $menuItems {
  1069.     hook::register requireOpenWindowsHook [list spssMenu $i] 1
  1070. unset i menuItems 
  1071.  
  1072. # Now we actually build the SPSS menu.
  1073.  
  1074. menu::buildSome spssMenu
  1075.  
  1076. # ===========================================================================
  1077. # ◊◊◊◊ SPSS menu support ◊◊◊◊ #
  1078.  
  1079. # This is the procedure called for all main menu items.
  1080.  
  1081. proc SPSS::menuProc {menu item} {SPSS::$item}
  1082.  
  1083. # Give a beta message for untested features / menu items.
  1084.  
  1085. proc SPSS::betaMessage {{kill 1}} {
  1086.     
  1087.     beep ; message "Sorry, this feature has not been fully implemented."
  1088.     if {$kill} {return -code return}
  1089. }
  1090.  
  1091. # ===========================================================================
  1092. # Open the SPSS/PSPP Home Page
  1093.  
  1094. proc SPSS::spssHomePage {{app "SPSS"}} {
  1095.     
  1096.     global SPSSmodeVars
  1097.     
  1098.     if {$app == ""} {set app $SPSSmodeVars(application)}
  1099.     set lowApp [string tolower $app]
  1100.     
  1101.     url::execute $SPSSmodeVars(${lowApp}HomePage)
  1102. }
  1103.  
  1104. proc SPSS::psppHomePage {} {SPSS::spssHomePage "PSPP"}
  1105.  
  1106. # ===========================================================================
  1107. # Switch to SPSS or PSPP application
  1108.  
  1109. proc SPSS::switchToSpss {{app "SPSS"}} {
  1110.     
  1111.     global SPSSmodeVars
  1112.     
  1113.     if {$app == ""} {set app $SPSSmodeVars(application)}
  1114.     app::launchFore [SPSS::sig $app]
  1115. }
  1116.  
  1117. proc SPSS::switchToPspp {} {SPSS::switchToSpss "PSPP"}
  1118.  
  1119. # ===========================================================================
  1120. # Return the SPSS / PSPP signature.  
  1121.  
  1122. proc SPSS::sig {{app "SPSS"}} {
  1123.     
  1124.     global SPSSmodeVars tcl_platform
  1125.     
  1126.     if {$app == ""} {set app $SPSSmodeVars(application)}
  1127.  
  1128.     set lowApp [string tolower $app]
  1129.     set capApp [string toupper $app]
  1130.     set pf     $tcl_platform(platform)
  1131.  
  1132.     if {$pf == "macintosh"} {
  1133.         # Make sure that the Macintosh application for the signature exists.
  1134.         if {[catch {nameFromAppl $SPSSmodeVars(${lowApp}Sig)}]} {
  1135.             alertnote "Looking for the $capApp application ..."
  1136.             S::setApplication $lowApp
  1137.         }
  1138.     } elseif {$pf == "windows" || $pf == "unix"} {
  1139.         # Make sure that the Windows application for the signature exists. 
  1140.         # We assume that this will work for unix, too.
  1141.         if {![file exists $SPSSmodeVars(${lowApp}Sig)]} {
  1142.             alertnote "Looking for the $capApp application ..."
  1143.             SPSS::setApplication $lowApp
  1144.         }
  1145.     }
  1146.     return $SPSSmodeVars(${lowApp}Sig)
  1147. }
  1148.  
  1149. # ===========================================================================
  1150. # Set Application
  1151. # Prompt the user to locate the local application for either SPSS or PSPP.
  1152.  
  1153. proc SPSS::setApplication {{app ""}} {
  1154.     
  1155.     global mode SPSSmodeVars
  1156.     
  1157.     if {$app == ""} {
  1158.         set app $SPSSmodeVars(application)
  1159.     } 
  1160.     set lowApp [string tolower $app]
  1161.     set capApp [string toupper $app]
  1162.     
  1163.     set newSig ""
  1164.     set newSig [dialog::askFindApp $capApp $SPSSmodeVars(${lowApp}Sig)]
  1165.     
  1166.     if {$newSig != ""} {
  1167.         set SPSSmodeVars(${lowApp}Sig) "$newSig"
  1168.         set oldMode $mode
  1169.         set mode "SPSS"
  1170.         synchroniseModeVar "${lowApp}Sig" $SPSSmodeVars(${lowApp}Sig)
  1171.         set mode $oldMode
  1172.         message "The $capApp signature has been changed to \"$newSig\"."
  1173.     } else {
  1174.         message "Cancelled."
  1175.     }
  1176. }
  1177.  
  1178. # ===========================================================================
  1179. # ◊◊◊◊ Help ◊◊◊◊ #
  1180.  
  1181. proc SPSS::helpProc {menu item} {
  1182.  
  1183.     global SPSSmodeVars SPSSPrefsInMenu
  1184.     
  1185.     if {$item == "wwwCommandHelp"} {
  1186.         SPSS::wwwCommandHelp
  1187.     } elseif  {$item == "localCommandHelp"} {
  1188.         SPSS::localCommandHelp
  1189.     } elseif {$item == "pspp" || $item == "spss"} {
  1190.         SPSS::selectApplication $item
  1191.         SPSS::rebuildMenu
  1192.     } elseif {[lsearch -exact $SPSSPrefsInMenu $item] != -1} {
  1193.         SPSS::flagFlip $item
  1194.         SPSS::rebuildMenu spssHelp
  1195.         SPSS::rebuildMenu psppHelp
  1196.     } elseif {$item == "setSpssApplication"} {
  1197.         SPSS::setApplication "SPSS"
  1198.     } elseif {$item == "setPsppApplication"} {
  1199.         SPSS::setApplication "SPSS"
  1200.     } elseif {$item == "spssModeHelp"} {
  1201.         package::helpFile "SPSS"
  1202.     } else {
  1203.         SPSS::$item
  1204.     } 
  1205. }
  1206.  
  1207. # Choose between SPSS and PSPP
  1208.  
  1209. proc SPSS::selectApplication {app} {
  1210.     
  1211.     global mode SPSSmodeVars
  1212.     
  1213.     set app [string toupper $app]
  1214.  
  1215.     set oldMode $mode
  1216.     set mode "SPSS"
  1217.     set SPSSmodeVars(application) $app
  1218.     set mode $oldMode
  1219.     synchroniseModeVar application $SPSSmodeVars(application)
  1220.     message "Default application is now $app."
  1221. }
  1222.  
  1223. # ===========================================================================
  1224. # ◊◊◊◊ Keywords ◊◊◊◊ #
  1225.  
  1226. proc SPSS::keywordsProc {menuName item} {
  1227.  
  1228.     global SPSSlowerCaseCmds
  1229.     
  1230.     if {$item == "listKeywords"} {
  1231.         set keywords [listpick -l -p "Current SPSS mode keywords…" $SPSSlowerCaseCmds]
  1232.         foreach keyword $keywords {
  1233.             SPSS::checkKeywords $keyword
  1234.         }
  1235.     } elseif {$item == "addNewCommands" || $item == "addNewOptions"} {
  1236.         set item [string trimleft $item "addNew"]
  1237.         if {$item == "Commands" && [llength [winNames]] && [askyesno \
  1238.           "Would you like to add all of the \"extra\" commands from this window\
  1239.           to the \"Add Commands\" preference?"] == "yes"} {
  1240.             SPSS::addWindowCommands
  1241.         } else {
  1242.             SPSS::addKeywords $item
  1243.         }
  1244.     } else {
  1245.         SPSS::$item
  1246.     } 
  1247. }
  1248.  
  1249. # ===========================================================================
  1250. # SPSS::addWindowCommands
  1251. # Add all of the "extra" commands which appear in entries in this window.
  1252.  
  1253. proc SPSS::addWindowCommands {} {
  1254.     
  1255.     global mode SPSScmds SPSSmodeVars
  1256.     
  1257.     if {![llength [winNames]]} {
  1258.         message "Cancelled -- no current window!"
  1259.         return
  1260.     } 
  1261.     
  1262.     message "Scanning [win::CurrentTail] for all commands…"
  1263.     
  1264.     set pos [minPos]
  1265.     set pat {^([a-zA-Z0-9]+[a-zA-Z0-9])+[\t ]}
  1266.     while {![catch {search -f 1 -r 1 $pat $pos} match]} {
  1267.         set pos [nextLineStart [lindex $match 1]]
  1268.         set commandLine [getText [lindex $match 0] [lindex $match 1]]
  1269.         regexp $pat $commandLine match aCommand
  1270.         set aCommand [string tolower $aCommand]
  1271.         if {![lcontains SPSScmds $aCommand]} {
  1272.             append SPSSmodeVars(addCommands) " $aCommand"
  1273.         } 
  1274.     }
  1275.     set SPSSmodeVars(addCommands) [lsort [lunique $SPSSmodeVars(addCommands)]]
  1276.     set oldMode $mode
  1277.     set mode "SPSS"
  1278.     synchroniseModeVar addCommands $SPSSmodeVars(addCommands)
  1279.     set mode $oldMode
  1280.     if {[llength $SPSSmodeVars(addCommands)]} {
  1281.         SPSS::colorizeSPSS
  1282.         listpick -p "The \"Add Commands\" preference includes:" \
  1283.           $SPSSmodeVars(addCommands)
  1284.         message "Use the \"Mode Prefs --> Preferences\" menu item to edit keyword lists."
  1285.     } else {
  1286.         message "No \"extra\" commands from this window were found."
  1287.     } 
  1288. }
  1289.  
  1290. proc SPSS::addKeywords {{category} {keywords ""}} {
  1291.     
  1292.     global mode SPSSmodeVars    
  1293.  
  1294.     if {$keywords == ""} {
  1295.         set keywords [prompt "Enter new SPSS $category:" ""]
  1296.     }
  1297.  
  1298.     # The list of keywords should all be lower case.
  1299.     set keywords [string tolower $keywords]
  1300.     # Check to see if the keyword is already defined.
  1301.     foreach keyword $keywords {
  1302.         set checkStatus [SPSS::checkKeywords $keyword 1 0]
  1303.         if {$checkStatus != 0} {
  1304.             alertnote "Sorry, \"$keyword\" is already defined\
  1305.               in the $checkStatus list."
  1306.             message "Cancelled."
  1307.             return -code return
  1308.         } 
  1309.     }
  1310.     # Keywords are all new, so add them to the appropriate mode preference.
  1311.     lappend SPSSmodeVars(add$category) $keywords
  1312.     set SPSSmodeVars(add$category) [lsort $SPSSmodeVars(add$category)]
  1313.     set oldMode $mode
  1314.     set mode "SPSS"
  1315.     synchroniseModeVar add$category $SPSSmodeVars(add$category)
  1316.     set mode $oldMode
  1317.     SPSS::colorizeSPSS
  1318.     message "\"$keywords\" added to $category preference."
  1319. }
  1320.  
  1321. proc SPSS::checkKeywords {{newKeywordList ""} {quietly 0} {noPrefs 0}} {
  1322.     
  1323.     global SPSSmodeVars
  1324.     
  1325.     global SPSSmodeVars SPSSCommands SPSSUserCommands SPSSFunctions SPSSOperators  
  1326.     
  1327.     set type 0
  1328.     if {$newKeywordList == ""} {
  1329.         set quietly 0
  1330.         set newKeywordList [prompt "Enter SPSS mode keywords to be checked:" ""]
  1331.     }
  1332.     # Check to see if the new keyword(s) is already defined.
  1333.     foreach newKeyword $newKeywordList {
  1334.         set newKeyword [string tolower $newKeyword]
  1335.         if {[lsearch -exact $SPSSCommands $newKeyword] != "-1"} {
  1336.             set type SPSSCommands
  1337.         } elseif {[lsearch -exact $SPSSUserCommands $newKeyword] != "-1"} {
  1338.             set type SPSSUserCommands
  1339.         } elseif {[lsearch -exact $SPSSmodeVars(addCommands) $newKeyword] != "-1"} {
  1340.             set type SPSSmodeVars(addCommands)
  1341.         } elseif {!$noPrefs && \
  1342.           [lsearch -exact $SPSSFunctions $newKeyword] != "-1"} {
  1343.             set type SPSSFunctions
  1344.         } elseif {!$noPrefs && \
  1345.           [lsearch -exact $SPSSOperators $newKeyword] != "-1"} {
  1346.             set type SPSSOperators
  1347.         }
  1348.         if {$quietly} {
  1349.             # When this is called from other code, it should only contain
  1350.             # one keyword to be checked, and we'll return it's type.
  1351.             return "$type"
  1352.         } elseif {!$quietly && $type == 0} {
  1353.             alertnote "\"$newKeyword\" is not currently defined\
  1354.               as a SPSS mode keyword"
  1355.         } elseif {$type != 0} {
  1356.             # This will work for any other value for "quietly", such as 2
  1357.             alertnote "\"$newKeyword\" is currently defined as a keyword\
  1358.               in the \"$type\" list."
  1359.         } 
  1360.         set type 0
  1361.     }
  1362. }
  1363.  
  1364. # ===========================================================================
  1365. # ◊◊◊◊ Processing ◊◊◊◊ #
  1366.  
  1367. # ===========================================================================
  1368. # Process File
  1369. # Send entire file to SPSS for processing, adding carriage return at end
  1370. # of file if necessary.
  1371. # Optional "f" argument allows this to be called by other code, or to be 
  1372. # sent via a Tcl shell window.
  1373.  
  1374. proc SPSS::processFile {{f ""} {app ""}} {
  1375.     
  1376.     global SPSSmodeVars
  1377.     
  1378.     if {$f != ""} {file::openAny $f}
  1379.     set f [win::Current]
  1380.  
  1381.     if {$app == ""} {set app $SPSSmodeVars(application)}
  1382.  
  1383.     set lowApp [string tolower $app]
  1384.     set capApp [string toupper $app]
  1385.  
  1386.     set dirtyWindow [winDirty]
  1387.     set dontSave 0
  1388.     if {$dirtyWindow && [askyesno \
  1389.       "Do you want to save the file before sending it to $capApp?"] == "yes"} {
  1390.         save
  1391.     } else {
  1392.         set dontSave 1
  1393.     } 
  1394.     if {!$dontSave && [lookAt [pos::math [maxPos] - 1]] != "\r"} {
  1395.         set pos [getPos]
  1396.         goto [maxPos]
  1397.         insertText "\r"
  1398.         goto $pos
  1399.         alertnote "Carriage return added to end of file."
  1400.         save
  1401.     }
  1402.  
  1403.     app::launchBack '[SPSS::sig $capApp]'
  1404.     sendOpenEvent noReply '[SPSS::sig $capApp]' $f
  1405.     switchTo '[SPSS::sig $capApp]'
  1406. }
  1407.  
  1408.  
  1409. # ===========================================================================
  1410. # Process Selection
  1411. # Procedure to implement transfer of selected lines to SPSS for processing.
  1412.  
  1413. proc SPSS::processSelection {{selection ""} {app ""}} {
  1414.     
  1415.     global PREFS SPSSmodeVars
  1416.     
  1417.     if {$app == ""} {set app $SPSSmodeVars(application)}
  1418.  
  1419.     set lowApp [string tolower $app]
  1420.     set capApp [string toupper $app]
  1421.  
  1422.     if {$selection == ""} {
  1423.         if {![isSelection]} {
  1424.             message "No selection -- cancelled."
  1425.             return
  1426.         } else {
  1427.             set selection [getSelect]
  1428.         } 
  1429.     }
  1430.     file::ensureDirExists [file join $PREFS SPSS-tmp]
  1431.     set newFile [file join $PREFS SPSS-tmp temp-SPSS.s]
  1432.     file::writeAll $newFile $selection 1
  1433.  
  1434.     app::launchBack '[SPSS::sig $capApp]'
  1435.     sendOpenEvent noReply '[SPSS::sig $capApp]' $newFile
  1436.     switchTo '[SPSS::sig $capApp]'
  1437. }
  1438.  
  1439. proc SPSS::quitHook {} {temp::cleanup SPSS-tmp}
  1440.  
  1441. # ===========================================================================
  1442. # ◊◊◊◊ Marks ◊◊◊◊ #
  1443.  
  1444. proc SPSS::markFileProc {menu item} {
  1445.  
  1446.     if {$item == "source"} {
  1447.         SPSS::MarkFile {.sps}
  1448.     } elseif  {$item == "output"} {
  1449.         # doesn't really matter what we put for the mark file "type" here,
  1450.         # since output is the default if other "if ..." cases aren't met.
  1451.         SPSS::MarkFile {.out}
  1452.     } elseif  {$item == "freqFile"} {
  1453.         SPSS::MarkFile {.freq}
  1454.     } elseif {$item == "autoMark"} {
  1455.         SPSS::flagFlip autoMark
  1456.         SPSS::rebuildMenu markSpssFileAs…
  1457.         SPSS::rebuildMenu markPsppFileAs…
  1458.     }
  1459. }
  1460.  
  1461. # ===========================================================================
  1462. # ◊◊◊◊ Insertions ◊◊◊◊ #
  1463.  
  1464. proc SPSS::insertPath {} {
  1465.     
  1466.     global file::separator
  1467.     
  1468.     set path ""
  1469.     set t    ""
  1470.     append t "\"${file::separator}"
  1471.     set path [getfile "Choose path of target file:"]
  1472.     if {$path != ""} {
  1473.         append t $path
  1474.         append t "\""
  1475.         insertText $t
  1476.     }
  1477. }
  1478.  
  1479. # ===========================================================================
  1480. # ◊◊◊◊ Navigation ◊◊◊◊ #
  1481.  
  1482. # Next/Prev command can simply return the position of the next command
  1483. # (quietly == 1), move the cursor to the next command (placing the cursor
  1484. # at the top of the window if toTop == 1), extend the current selection to
  1485. # the end of the this command, or (if the current command is already
  1486. # highlighted in its entirety) extend the current selection to the end of
  1487. # the next command.
  1488.  
  1489. proc SPSS::nextCommand {{quietly 0} {toTop 0}} {
  1490.     
  1491.     if {[pos::compare [selEnd] == [maxPos]]} {
  1492.         set pos [maxPos]
  1493.     } else {
  1494.         set pos [pos::math [selEnd] + 1]
  1495.     } 
  1496.     set pat {^[^\r\n\t \*/]}
  1497.  
  1498.     if {![catch {search -f 1 -r 1 $pat $pos} match]} {
  1499.         set pos [lineStart [lindex $match 1]]
  1500.     } else {
  1501.         set pos [maxPos]
  1502.     }
  1503.     if {$quietly} {
  1504.     return $pos
  1505.     } elseif {[isSelection]} {
  1506.     set limit1 [lindex [SPSS::getCommand [selEnd]] 1]
  1507.     set limit2 [lindex [SPSS::getCommand $pos    ] 1]
  1508.     if {$limit2 == "-1"} {set limit2 [maxPos]}
  1509.     if {$limit1 == "-1"} {set limit1 $limit2}
  1510.     if {[pos::compare [selEnd] < $limit1]} {
  1511.         select [getPos] $limit1
  1512.     } else {
  1513.         select [getPos] $limit2
  1514.     } 
  1515.     } elseif {$pos == [maxPos]} {
  1516.     message "No further commands in the file."
  1517.     return
  1518.     } else {
  1519.     goto $pos
  1520.     message [getText $pos [nextLineStart $pos]]
  1521.     } 
  1522.     if {$toTop} {insertToTop}
  1523. }
  1524.  
  1525. proc SPSS::prevCommand {{quietly 0} {toTop 0}} {
  1526.     
  1527.     if {[pos::compare [getPos] == [minPos]]} {
  1528.         set pos [minPos]
  1529.     } else {
  1530.         set pos [pos::math [getPos] - 1]
  1531.     } 
  1532.     set pat {^[^\r\n\t \*/]}
  1533.  
  1534.     if {![catch {search -f 0 -r 1 $pat $pos} match]} {
  1535.         set pos [lineStart [lindex $match 1]]
  1536.     } else {
  1537.         set pos [minPos]
  1538.     }
  1539.     if {$quietly} {
  1540.     return $pos
  1541.     } elseif {[isSelection]} {
  1542.     # Going backwards is actually easier with selections.
  1543.     select $pos [selEnd]
  1544.     } elseif {$pos == [minPos]} {
  1545.     message "No further commands in the file."
  1546.     return
  1547.     } else {
  1548.     goto $pos
  1549.     message [getText $pos [nextLineStart $pos]]
  1550.     } 
  1551.     if {$toTop} {insertToTop}
  1552.     return $pos
  1553. }
  1554.  
  1555. proc SPSS::selectCommand {} {
  1556.     
  1557.     set pos    [getPos]
  1558.     set limits [SPSS::getCommand $pos]
  1559.     set posBeg [lindex $limits 0]
  1560.     set posEnd [lindex $limits 1]
  1561.     
  1562.     if {$posBeg != "-1" && $posEnd != "-1" && \
  1563.       [pos::compare $pos >= $posBeg] && [pos::compare $pos <= $posEnd]} {
  1564.         select $posBeg $posEnd
  1565.     } else {
  1566.         message "The cursor is not within a command."
  1567.         error "The cursor is not within a command."
  1568.     } 
  1569. }
  1570.  
  1571. proc SPSS::copyCommand {{quietly 0}} {
  1572.     
  1573.     set pos [getPos]
  1574.     if {[set posBeg [lindex [SPSS::getCommand $pos] 0]] != "-1"} {
  1575.         goto $posBeg
  1576.         forwardWord
  1577.         set posEnd [getPos]
  1578.         if {!$quietly} {
  1579.             select $posBeg $posEnd
  1580.             copy
  1581.             message "\"[getText $posBeg $posEnd]\" copied to clipboard."
  1582.         } 
  1583.         goto $pos
  1584.         return [getText $posBeg $posEnd]
  1585.     } elseif {!$quietly} {
  1586.         message "The cursor is not within a command."
  1587.     }
  1588.     return ""
  1589. }
  1590.  
  1591. proc SPSS::reformatCommand {} {
  1592.     
  1593.     if {![isSelection]} {SPSS::selectCommand} 
  1594.     message "Reformatting …"
  1595.     ::indentRegion
  1596.     goto [pos::math [getPos] -1]
  1597.     goto [SPSS::nextCommand 1]
  1598.     message "Reformatted."
  1599. }
  1600.  
  1601. proc SPSS::getCommand {pos} {
  1602.     
  1603.     set pos1 [pos::math [nextLineStart $pos] - 1]
  1604.     set pat {^[^\r\n\t \}\)]}
  1605.     set posBeg "-1"
  1606.     set posEnd "-1"
  1607.     if {![catch {search -f 0 -r 1 $pat $pos1} match]} {
  1608.         set posBeg [lindex $match 0]
  1609.         set pos2   [nextLineStart $posBeg]
  1610.         if {![catch {search -f 1 -r 1 $pat $pos2} match]} {
  1611.             set posEnd [lindex $match 0]
  1612.         } else {
  1613.             set posEnd [maxPos]
  1614.         } 
  1615.         # Now back up to remove empty or commented lines.
  1616.         set posEndPrev [pos::math $posEnd - 1]
  1617.         set prevLine [getText [lineStart $posEndPrev] $posEndPrev]
  1618.         while {[regexp {^[\t ]*$} $prevLine]} {
  1619.             set posEnd [lineStart $posEndPrev]
  1620.             set posEndPrev [pos::math $posEnd - 1]
  1621.             set prevLine [getText [lineStart $posEndPrev] $posEndPrev]
  1622.         }
  1623.     } 
  1624.     return [list $posBeg $posEnd]
  1625. }
  1626.  
  1627. # ===========================================================================
  1628. # ◊◊◊◊ --------------------- ◊◊◊◊ #
  1629. # ◊◊◊◊ version history ◊◊◊◊ #
  1630. #  modified by  vers#  reason
  1631. #  -------- --- ------ -----------
  1632. #  01/28/20 cbu 1.0.1  First created SPSS mode, based upon other modes found 
  1633. #                        in Alpha's distribution.  Commands are based on 
  1634. #                        version 4.0 of SPSS.
  1635. #  03/02/20 cbu 1.0.2  Minor modifications to comment handling.
  1636. #  03/20/00 cbu 1.0.3  Minor update of keywords dictionaries.
  1637. #  04/01/00 cbu 1.0.4  Added new preferences to allow the user to enter 
  1638. #                        additional commands, arguments, and symbols.  
  1639. #                      Added "Update Colors" proc to avoid need for a restart
  1640. #  04/08/00 cbu 1.0.5  Unset obsolete preferences from earlier versions.
  1641. #                      Added "Continue Comment", "Electric Return Over-ride",
  1642. #                        and "Electric Period".
  1643. #                      Renamed "Update Colors" to "Update Preferences".
  1644. #  04/16/00 cbu 1.1    Renamed to spssMode.tcl
  1645. #                      Added "Mark File" and "Parse Functions" procs.
  1646. #  06/22/00 cbu 1.2    "Mark File" now recognizes headings as well as commands.
  1647. #                      "Mark File" recognizes source or output files.
  1648. #                      Completions, Completions Tutorial added.
  1649. #                      "Reload Completions", referenced by "Update Preferences".
  1650. #                      Better support for user defined keywords.
  1651. #                      Removed "Continue Comment", now global in Alpha 7.4.
  1652. #                      Added command double-click for on-line help.
  1653. #                      <shift, control>-<command> double-click syntax info.
  1654. #                        (Foundations, at least.  Ongoing project.)
  1655. #  08/08/00 cbu 1.2.1  Minor electric completions bug fixes.
  1656. #                      Added message if no matching ")".
  1657. #                      Mark File ignores "execute" commands.
  1658. #                      Mark File can mark a frequencies file.
  1659. #                      Beta-version of an SPSS menu, based on the Stata menu.
  1660. #                      Added "spssSig" preference to allow user to find
  1661. #                        local application if necessary.
  1662. #                      Added SPSS::sig which returns SPSS signature.
  1663. #  08/28/00 cbu 1.2.2  Added some of the flag preferences to "SPSS Help" menu.
  1664. #                      Added "flagFlip" to update preference bullets in menu.
  1665. #                      Added a "noHelpKey" preference, which switches the
  1666. #                        "help" key binding to F8.
  1667. #                      Added "Add New Commands / Arguments" to "SPSS Help" menu.
  1668. #                      Added "Set SPSS Application to "SPSS Help" menu.
  1669. #  11/05/00 cbu 1.3    Added "next/prevCommand", "selectCommand", and
  1670. #                        "copyCommand" procs to menu.
  1671. #                      Added "SPSS::indentLine".
  1672. #                      Added "SPSS::reformatCommand" to menu.
  1673. #                      "SPSS::reloadCompletions" is now obsolete.
  1674. #                      "SPSS::updatePreferences" is now obsolete.
  1675. #                      "SPSS::colorizeSPSS" now takes care of setting all 
  1676. #                        keyword lists, including SPSScmds.
  1677. #                      Cleaned up completion procs.  This file never has to be
  1678. #                        reloaded.  (Similar cleaning up for "SPSS::DblClick").
  1679. #  11/16/00 cbu 2.0    New url prefs handling requires 7.4b21
  1680. #                      Added "Home Page" pref, menu item.
  1681. #                      Removed  hook::register requireOpenWindowsHook from
  1682. #                        mode declaration, put it after menu build.
  1683. #  12/19/00 cbu 2.1    The menu proc "Add Commands" now includes an option
  1684. #                        to grab all of the "extra" command from the current
  1685. #                        window, using SPSS::addWindowCommands.
  1686. #                      Added "Keywords" submenu, "List Keywords" menu item.
  1687. #                      Big cleanup of ::sig, ::setApplication, processing ...
  1688. #  01/25/01 cbu 2.1.1  Bug fix for SPSS::processSelection/File.
  1689. #                      Better frequency file marking.
  1690. #                      Bug fix for comment characters.
  1691.  
  1692. # ===========================================================================
  1693. # .
  1694.